#!/usr/bin/env python

import oauth.oauth as oauth
import httplib


SERVER = "www.douban.com"
API_SERVER = "api.douban.com"
PORT = httplib.HTTP_PORT
API_HOST = 'http://api.douban.com'
OAUTH_HOST = 'http://www.douban.com'
REQUEST_TOKEN_URL = OAUTH_HOST + '/service/auth/request_token'
ACCESS_TOKEN_URL = OAUTH_HOST + '/service/auth/access_token'
AUTHORIZATION_URL = OAUTH_HOST + '/service/auth/authorize'


class OAuthClient:
    def __init__(self,
                 consumer_key,
                 consumer_key_secret,
                 server=SERVER,
                 port=PORT,
                 api_host=API_HOST,
                 oauth_host=OAUTH_HOST,
                 request_token_url=REQUEST_TOKEN_URL,
                 access_token_url=ACCESS_TOKEN_URL,
                 authorization_url=AUTHORIZATION_URL,
                 callback_url=None):
        self.consumer_key = consumer_key
        self.consumer_key_secret = consumer_key_secret
        self.server = server
        self.port = port
        self.api_host = api_host
        self.oauth_host = oauth_host
        self.request_token_url = request_token_url
        self.access_token_url = access_token_url
        self.authorization_url = authorization_url
        self.callback_url = callback_url
        self.consumer = oauth.OAuthConsumer(self.consumer_key, self.consumer_key_secret)
        self.token = None
        self.signature_method = oauth.OAuthSignatureMethod_PLAINTEXT()
    
    def login(self, key=None, secret=None, function=None):
        if key and secret:
            self.token = oauth.OAuthToken(key, secret)
            return
        try:
            self.token = self.__fetch_request_token__()
            self.__authorize_request_token__(self.token, function)
            self.token = self.__fetch_access_token__(self.token)
        except oauth.OAuthError as e:
            raise oauth.OAuthError(e.message)
   
    def __fetch_token__(self, oauth_request):
        response = None
        try:
            connection = httplib.HTTPConnection("%s:%d" % (self.server, self.port))
            connection.request(oauth_request.http_method, oauth_request.http_url, headers=oauth_request.to_header())            
            response = connection.getresponse().read()
            token = oauth.OAuthToken.from_string(response)
            if token == None:
                raise oauth.OAuthError('')
            return token
        except oauth.OAuthError:
            raise oauth.OAuthError('__fetch_token__: url %s request error\n response is:\n %s' % (oauth_request.http_url, response))  
   
    def __fetch_request_token__(self):
        try:
            oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, http_method='GET', http_url=self.request_token_url)
            oauth_request.sign_request(self.signature_method, self.consumer, token=None)
            return self.__fetch_token__(oauth_request)
        except oauth.OAuthError as e:
            raise oauth.OAuthError('__fetch_request_token__: fetch request token error, %s' % e.message)
  
    def __authorize_request_token__(self, token, function=None):
        try:
            oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token, self.callback_url, http_method='GET', http_url=self.authorization_url)
            function(oauth_request.to_url())
        except oauth.OAuthError:
            raise oauth.OAuthError('__authorize_request_token__: authorize request token error for token key=%s, secret=%' % (token.key, token.secret))
   
    def __fetch_access_token__(self, token): 
        assert token is not None
        try:
            oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token, http_method='GET', http_url=self.access_token_url)
            oauth_request.sign_request(self.signature_method, self.consumer, token) 
            return self.__fetch_token__(oauth_request)
        except:
            raise oauth.OAuthError('__fetch_access_token__: fetch access token error for token key=%s, secret=%' % (token.key, token.serect))
    
    def get_authorize_url(self, key, secret, callback=None):
            token = oauth.OAuthToken(key, secret)
            oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token, callback, http_method='GET', http_url=self.authorization_url)
            return oauth_request.to_url()
    
    def get_oauth_header(self, method, uri, parameter={}):
        if self.token:
            try:
                if not uri.startswith('http'):
                    uri = self.api_host + uri
                oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, 
                        token=self.token, http_method=method, http_url=uri, parameters=parameter)
                oauth_request.sign_request(self.signature_method, self.consumer, self.token)
                return oauth_request.to_header()
            except:
                raise oauth.OAuthError('get_oauth_header: get oauth header error method=%s, uri=%s' % (method, uri))
        else:
            return {}
    def access_resource(self, method, uri, body=None, content_type="application/atom+xml", charset="utf-8"):
        if self.token:
            try:
                oauth_request = oauth.OAuthRequest.from_consumer_and_token(self.consumer, token=self.token, http_method=method, http_url=uri)
                oauth_request.sign_request(self.signature_method, self.consumer, self.token)
                headers = oauth_request.to_header()
                if method in ('POST', 'PUT'):
                    headers['Content-Type'] = '%s; %s' % (content_type, charset)  
                connection = httplib.HTTPConnection("%s:%d" % (self.server, self.port))
                connection.request(method, uri, body=body, headers=headers) 
                return connection.getresponse() 
            except:
                raise oauth.OAuthError('access_resource: access resource error, method=%s, uri=%s, body=%s, content_type=%s, charset=%s' % (method, uri, body, content_type, charset))
        else:
            raise oauth.OAuthError('access_resource: access resource error, token is None!')        
        
        
        
        
        
        
          
